package com.clay.appointment.common.exception;

import com.clay.appointment.common.response.ResultEnum;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 全局异常
 * </p>
 *
 * @author Yohann
 * @since 2020/9/21
 */
@Slf4j
public class GlobalException extends RuntimeException {
    private Integer code;

    /**
     * 私有全参构造
     *
     * @param code    状态码
     * @param message 信息
     */
    private GlobalException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    /**
     * 私有全参构造
     *
     * @param code    状态码
     * @param message 信息
     * @param cause   异常原因
     */
    private GlobalException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    /**
     * 通过异常枚举值构建异常
     *
     * @param exceptionEnum 异常枚举
     */
    private GlobalException(ExceptionEnum exceptionEnum) {
        super(exceptionEnum.getMessage());
        this.code = exceptionEnum.getCode();
    }

    /**
     * 通过异常枚举值构建异常
     *
     * @param exceptionEnum 异常枚举
     * @param cause         异常原因
     */
    private GlobalException(ExceptionEnum exceptionEnum, Throwable cause) {
        super(exceptionEnum.getMessage(), cause);
        this.code = exceptionEnum.getCode();
    }

    public static void throwOut() {
        throwOut(ExceptionEnum.UNDEFINED);
    }

    /**
     * 获取状态码
     *
     * @return 状态码
     */
    public Integer getCode() {
        return code;
    }

    /**
     * 通过异常枚举抛出异常
     *
     * @param exceptionEnum 异常枚举
     */
    public static void throwOut(ExceptionEnum exceptionEnum) {
        throw new GlobalException(exceptionEnum);
    }

    /**
     * 通过异常状态、信息抛出异常
     *
     * @param code    状态码
     * @param message 状态信息
     */
    public static void throwOut(Integer code, String message) {
        throw new GlobalException(code, message);
    }

    /**
     * 通过异常状态、信息抛出异常
     *
     * @param exceptionEnum 异常枚举
     * @param message       状态信息
     */
    public static void throwOut(ExceptionEnum exceptionEnum, String message) {
        throw new GlobalException(exceptionEnum.getCode(), message);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param message 状态信息
     */
    public static void throwOut(String message) {
        throw new GlobalException(ExceptionEnum.UNDEFINED.getCode(), message);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param message   状态信息
     * @param throwable 异常信息
     */
    public static void throwOut(String message, Throwable throwable) {
        throw new GlobalException(ExceptionEnum.UNDEFINED.getCode(), message, throwable);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param throwable 异常信息
     */
    public static void throwOut(Throwable throwable) {
        throw new GlobalException(ExceptionEnum.UNDEFINED.getCode(), throwable.getMessage(), throwable);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param exceptionEnum 异常枚举
     * @param throwable     异常信息
     */
    public static void throwOut(ExceptionEnum exceptionEnum, Throwable throwable) {
        throw new GlobalException(exceptionEnum, throwable);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param exceptionEnum 异常枚举
     * @param throwable     异常信息
     */
    public static void throwOut(ExceptionEnum exceptionEnum, String message, Throwable throwable) {
        throw new GlobalException(exceptionEnum.getCode(), message, throwable);
    }

    /**
     * 通过异常信息抛出异常
     * 采用503状态码
     *
     * @param code      状态码
     * @param message   状态信息
     * @param throwable 异常信息
     */
    public static void throwOut(Integer code, String message, Throwable throwable) {
        throw new GlobalException(code, message, throwable);
    }

    /**
     * 通过异常信息抛出异常
     *
     * @param code    状态码
     * @param message 状态信息
     */
    public static void throwOutNoRollbackException(Integer code, String message) {
        throw new NoRollbackException(code, message);
    }

    /**
     * 通过异常信息抛出异常
     * 采用200状态码
     *
     * @param message 状态信息
     */
    public static void throwOutNoRollbackException(String message) {
        throw new NoRollbackException(message);
    }

    /**
     * 事务不回滚异常
     */
    private static class NoRollbackException extends RuntimeException {
        private Integer code;


        public NoRollbackException(Integer code, String message) {
            super(message);
            this.code = code;
        }

        public NoRollbackException(String message) {
            super(message);
            this.code = ResultEnum.SUCCESS.getCode();
        }

        /**
         * 获取状态码
         *
         * @return 状态码
         */
        public Integer getCode() {
            return code;
        }
    }
}